package com.cll.learn.monitor.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cll.learn.monitor.bean.MethodInvokeInfo;
import com.cll.learn.monitor.task.ClearOvertimeTopPercentileTask;
import com.cll.learn.monitor.task.ConsoleTopPercentileTask;
import com.cll.learn.monitor.thread.BaseTask;
import com.cll.learn.monitor.thread.BaseThreadFactory;
import com.cll.learn.monitor.thread.DiscardAndRecordPolicy;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 描述信息:
 *
 * @author CLL
 * @version 1.0
 * @date 2020/10/10 13:43
 */
public class TopPercentileUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(TopPercentileUtil.class);

    public static final Map<String, List<MethodInvokeInfo>> METHOD_INVOKE_INFO_MAP = new ConcurrentHashMap<>(3);

    public static final ScheduledThreadPoolExecutor CLEAR_POOL = new ScheduledThreadPoolExecutor(1, new BaseThreadFactory("CLEAR-GROUP", "CLEAR-THREAD"), new DiscardAndRecordPolicy());

    public static final ScheduledThreadPoolExecutor CONSOLE_POOL = new ScheduledThreadPoolExecutor(1, new BaseThreadFactory("CONSOLE-GROUP", "CONSOLE-THREAD"), new DiscardAndRecordPolicy());


    static {
        CLEAR_POOL.scheduleAtFixedRate(new ClearOvertimeTopPercentileTask(), 60, 60, TimeUnit.SECONDS);
        CONSOLE_POOL.scheduleAtFixedRate(new ConsoleTopPercentileTask(), 5, 5, TimeUnit.SECONDS);
    }

    /**
     * 获取TopPercentile请求耗时
     * @param methodInvokeInfoList  耗时信息列表
     * @param rate  TopPercentile比例
     * @return  耗时
     */
    public static long getTopPercentile(List<MethodInvokeInfo> methodInvokeInfoList, double rate){
        if (CollectionUtils.isEmpty(methodInvokeInfoList)) {
            return -1L;
        }

        long targetEndTime = System.currentTimeMillis();
        long targetStartTime = targetEndTime - 60000;

        List<MethodInvokeInfo> targetList = methodInvokeInfoList
                .stream()
                .filter((MethodInvokeInfo methodInvokeInfo) -> methodInvokeInfo.getEndTime() < targetEndTime && methodInvokeInfo.getEndTime() > targetStartTime)
                .sorted(Comparator.comparingLong(MethodInvokeInfo::getExecutionTime))
                .collect(Collectors.toList());

        int index = (int) (targetList.size() * rate);

        if (index >= targetList.size()) {
            index--;
        }
        return targetList.get(index).getExecutionTime();
    }

    /**
     * 请求过期的请求
     */
    public static void clearOvertimeMethodInvokeInfoFromMap(){
        long minTime = System.currentTimeMillis() - 60000;
        TopPercentileUtil.METHOD_INVOKE_INFO_MAP.forEach((String methodName, List<MethodInvokeInfo> list) -> {
            LOGGER.info(methodName + "请求数量 = " + list.size());
        });
        TopPercentileUtil.METHOD_INVOKE_INFO_MAP.forEach((String methodName, List<MethodInvokeInfo> list) -> {
            list.removeIf((MethodInvokeInfo methodInvokeInfo) -> methodInvokeInfo.getEndTime() < minTime);
        });
        TopPercentileUtil.METHOD_INVOKE_INFO_MAP.forEach((String methodName, List<MethodInvokeInfo> list) -> {
            LOGGER.info(methodName + "请求数量 = " + list.size());
        });
    }
}
